﻿using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Scripting;
using Microsoft.Scripting.Ast;
using Microsoft.Linq.Expressions;

namespace DlrBasic.Parser.Ast
{
    class On : Statement
    {
        LineNumberTarget[] targets;
        DlrBasicExpression expression;
        bool isGosub;

        public On(SourceSpan span, DlrBasicExpression expression, 
            bool isGosub, LineNumberTarget[] targets)
            : base(span)
        {
            this.isGosub = isGosub;
            this.expression = expression;
            this.targets = targets;
        }

        protected internal override Expression Generate(DlrBasicGenerator generator, StateMemberGenerator stateParameter, LambdaBuilder builder)
        {
            DlrBasicExpression roundExpression = new VariableOrCall(SourceSpan.None,
                "CINT", new DlrBasicExpression[] { expression });

            Expression branchNumber = Expression.ConvertHelper(
                roundExpression.Generate(generator), typeof(int));

            LabelTarget label = Expression.Label();

            SwitchBuilder switchBuilder = Utils.Switch(branchNumber, label);
            for (int i = 0; i < targets.Length; i++)
            {
                Expression caseBlock;
                int state = generator.GetLineStatementNumber(targets[i].LineNumber);
                if (isGosub)
                {
                    Expression pushState = Expression.Call(stateParameter.GetGosubStackVariable(),
                        typeof(Runtime.DlrBasicGosubStack).GetMethod("PushState"),
                        Expression.Constant(generator.GetNextStatementNumber(this)));

                    caseBlock = Expression.Block(
                        pushState,
                        Expression.Assign(stateParameter.GetCurrentStatementVariable(), Expression.Constant(state)),
                        Expression.Break(label));
                }
                else
                {
                    caseBlock = Expression.Block(
                        Expression.Assign(stateParameter.GetCurrentStatementVariable(), Expression.Constant(state)),
                        Expression.Break(label));
                }

                switchBuilder.Case(i + 1, caseBlock);                
            }

            Expression defaultBody = Expression.Block(
                base.Generate(generator, stateParameter, builder),
                Expression.Break(label));

            switchBuilder.Default(defaultBody);

            return switchBuilder.ToExpression();
        }
    }
}
